package main

import (
	"fmt"
	"github.com/go-redis/redis"
	"time"
)

// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "192.168.0.7:63780",
		Password: "", // no password set
		DB:       0,  // use default DB
		PoolSize: 100, // 连接池大小
	})

	_, err = rdb.Ping().Result()
	return err
}

func redisExample() {
	err := rdb.Set("name", "张云雷", 0).Err()
	if err != nil {
		fmt.Printf("set score failed, err:%v\n", err)
		return
	}

	val, err := rdb.Get("score").Result()
	if err != nil {
		fmt.Printf("get score failed, err:%v\n", err)
		return
	}
	fmt.Println("score", val)

	val2, err := rdb.Get("name").Result()
	if err == redis.Nil {
		fmt.Println("name does not exist")
	} else if err != nil {
		fmt.Printf("get name failed, err:%v\n", err)
		return
	} else {
		fmt.Println("name", val2)
	}
	val3, err := rdb.HGet("user", "username").Result()
	if err == redis.Nil {
		fmt.Println("name does not exist")
	} else if err != nil {
		fmt.Printf("get name failed, err:%v\n", err)
		return
	} else {
		fmt.Println("username", val3)
	}
	// 获取 hash键
	val4, err := rdb.HGetAll("user").Result()
	if err != nil {
		// redis.nil 键不存在
		fmt.Printf("报错 err: %v\n", err)
	} else {
		fmt.Println(val4)
	}
	// 获取 hash 指定字段
	val5 := rdb.HMGet("user", "password", "username").Val()
	fmt.Println(val5)


}
func redisExample2() {
	zsetKey := "language_rank"
	languages := []redis.Z{
		redis.Z{Score: 90.0, Member: "Golang"},
		redis.Z{Score: 98.0, Member: "Java"},
		redis.Z{Score: 95.0, Member: "Python"},
		redis.Z{Score: 97.0, Member: "JavaScript"},
		redis.Z{Score: 99.0, Member: "C/C++"},
	}
	// ZADD
	num, err := rdb.ZAdd(zsetKey, languages...).Result()
	if err != nil {
		fmt.Printf("zadd failed, err:%v\n", err)
		return
	}
	fmt.Printf("zadd %d succ.\n", num)

	// 把Golang的分数加10
	newScore, err := rdb.ZIncrBy(zsetKey, 10.0, "Golang").Result()
	if err != nil {
		fmt.Printf("zincrby failed, err:%v\n", err)
		return
	}
	fmt.Printf("Golang's score is %f now.\n", newScore)

	// 取分数最高的3个
	ret, err := rdb.ZRevRangeWithScores(zsetKey, 0, 2).Result()
	if err != nil {
		fmt.Printf("zrevrange failed, err:%v\n", err)
		return
	}
	for _, z := range ret {
		fmt.Println(z.Member, z.Score)
	}

	// 取95~100分的
	op := redis.ZRangeBy{
		Min: "95",
		Max: "100",
	}
	ret, err = rdb.ZRangeByScoreWithScores(zsetKey, op).Result()
	if err != nil {
		fmt.Printf("zrangebyscore failed, err:%v\n", err)
		return
	}
	for _, z := range ret {
		fmt.Println(z.Member, z.Score)
	}
}

func RedisPipeLineDemo() {
	pipe := rdb.Pipeline()
	err := pipe.Set("zyl", 200000, 0).Err()
	fmt.Println(err)
	//Incr := pipe.Incr("zyl")
	err = pipe.HSet("gtt", "age", 10).Err()
	_ = pipe.Get("score").Val()
	//fmt.Println(val)
	//fmt.Println(val)
	// 接收处理结果
	val1, err := pipe.Exec()
	fmt.Println(val1)
	//fmt.Println(Incr.Val(), err)

}

func TxPipeLineDemo() {
	pipe := rdb.TxPipeline()
	_ = pipe.Set("tx_pipeline_counter", 9, 0).Err()
	incr := pipe.Incr("tx_pipeline_counter")
	val := pipe.Get("tx_pipeline_counter")
	pipe.Expire("tx_pipeline_counter", time.Hour)

	_, err := pipe.Exec()
	fmt.Println(incr.Val(), err)
	fmt.Println(val.Val())
}

func WatchDemo() {
	// 监视watch_count的值，并在值不变的前提下将其值+1
	key := "watch_count"
	err := rdb.Watch(func(tx *redis.Tx) error {
		n, err := tx.Get(key).Int()
		if err != nil && err != redis.Nil {
			return err
		}
		_, err = tx.Pipelined(func(pipe redis.Pipeliner) error {
			// 写自己的业务逻辑
			// 如果在此次处理内有其他客户端修改了监控的 key 值， 则此次交易失败
			time.Sleep(time.Second * 10)
			pipe.Set(key, n+1, 0)
			return nil
		})
		return err
	}, key)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("成功！")
}

func main() {
	if err := initClient(); err != nil {
		fmt.Printf("连接redis失败, err: %v\n", err)
		return
	}
	fmt.Println("连接redis成功")
	// 资源的回收
	defer rdb.Close()
	//redisExample()
	//redisExample2()
	//RedisPipeLineDemo()
	//TxPipeLineDemo()
	WatchDemo()

}
